package com.cha.chaApp.babyphysical.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cha.chaApp.babyphysical.dao.BabyPhysicalIndicatorsDao;
import com.cha.chaApp.babyphysical.dao.BabyStandardDataDao;
import com.cha.chaApp.babyphysical.param.BabyPhysicalIndicatorsParam;
import com.cha.chaApp.babyphysical.param.UpdateBabyPhysicalIndicatorsParam;
import com.cha.chaApp.babyphysical.service.BabyPhysicalIndicatorsService;
import com.cha.chaApp.babyphysical.vo.BabyAgeInfoVo;
import com.cha.chaApp.babyphysical.vo.BabyGrowthInfoVo;
import com.cha.chaApp.babyphysical.vo.ComparisonResultVo;
import com.cha.chaCommon.core.entity.BabyInfo;
import com.cha.chaCommon.core.entity.BabyPhysicalIndicators;
import com.cha.chaCommon.core.entity.BabyStandardData;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BabyPhysicalIndicatorsServiceImpl
        extends ServiceImpl<BabyPhysicalIndicatorsDao, BabyPhysicalIndicators>
        implements BabyPhysicalIndicatorsService {

    @Autowired
    private BabyPhysicalIndicatorsDao babyPhysicalIndicatorsDao;

    @Autowired
    private BabyStandardDataDao babyStandardDataDao;

    /**
     * 验证测量日期是否大于出生日期
     *
     * @param babyId         宝宝ID
     * @param measurementTime 测量日期
     * @return 验证通过返回true，不通过返回false，并在不通过时打印提示信息
     */
    private boolean validateMeasurementTime(Long babyId, LocalDate measurementTime) {
        if (babyId == null || measurementTime == null) {
            return false;
        }
        BabyInfo babyInfo = babyPhysicalIndicatorsDao.selectByBabyId(babyId);
        if (babyInfo == null) {
            return false;
        }
        if (measurementTime.isAfter(babyInfo.getBirthDate())) {
            return true;
        }
//        System.out.println("测量日期必须晚于出生日期,请修改");
        return false;
    }

    /**
     * 根据babyId获取 indicators 列表
     * @param babyId
     * @return
     */
    @Override
    public List<BabyPhysicalIndicators> getBabyPhysicalIndicatorsByBabyId(Long babyId) {
        if (babyId == null) {
            return Collections.emptyList();
        }
        return babyPhysicalIndicatorsDao.selectList(new QueryWrapper<BabyPhysicalIndicators>()
                .eq("baby_id", babyId));
    }

    /**
     * 新增 indicators
     * @param indicatorsParam
     * @return
     */
    @Override
    public boolean addBabyPhysicalIndicators(BabyPhysicalIndicatorsParam indicatorsParam) {
        // 将参数对象转换为目标对象，处理测量时间格式转换，从LocalDate转为LocalDateTime
        BabyPhysicalIndicators indicators = new BabyPhysicalIndicators();
        BeanUtils.copyProperties(indicatorsParam, indicators);
        if (indicatorsParam.getMeasurementTime()!= null) {
            indicators.setMeasurementTime(LocalDate.from(indicatorsParam.getMeasurementTime().atStartOfDay()));
        }
        // 验证测量日期是否大于出生日期
        if (!validateMeasurementTime(indicatorsParam.getBabyId(), indicators.getMeasurementTime())) {
            return false;
        }
        // 在保存数据前，可以在这里对数据进行一些预处理或验证操作
        return save(indicators);
    }

    /**
     * 根据 indicatorsId 更新 indicators
     * @param indicatorId
     * @param indicators
     * @return
     */
    @Override
    public boolean updateSomeFieldsById(Long indicatorId, UpdateBabyPhysicalIndicatorsParam indicators) {
        BabyPhysicalIndicators existingIndicators = babyPhysicalIndicatorsDao.selectById(indicatorId);
        if (existingIndicators == null) {
            return false;
        }
        // 获取更新后的测量时间
        LocalDate updatedMeasurementTime = indicators.getMeasurementTime();
        if (updatedMeasurementTime!= null &&!validateMeasurementTime(existingIndicators.getBabyId(), updatedMeasurementTime)) {
            return false;
        }
        int rowsAffected = babyPhysicalIndicatorsDao.updateSomeFieldsById(indicatorId, indicators);
        return rowsAffected > 0;
    }

    /**
     * 根据 indicatorsId 删除 indicators
     * @param indicatorId
     * @return
     */
    @Override
    public boolean deleteBabyPhysicalIndicatorsById(Long indicatorId) {
        return removeById(indicatorId);
    }

    /**
     * 根据 babyId 获取宝宝的成长信息: 月龄、身高、体重、头围
     * @param babyId
     * @return List<BabyGrowthInfoVo>
     */
    @Override
    public List<BabyGrowthInfoVo> getBabyGrowthInfoByBabyId(Long babyId) {

        // 检查 babyId 是否为空
        if (babyId == null || babyId <= 0) {
            return Collections.emptyList();
        }
        // 先根据babyId获取该宝宝的所有身体指标记录
        List<BabyPhysicalIndicators> indicatorsList = babyPhysicalIndicatorsDao.selectList(new QueryWrapper<BabyPhysicalIndicators>()
                .eq("baby_id", babyId));

        // 检查指标记录是否为空
        if (indicatorsList == null || indicatorsList.isEmpty()) {
            return Collections.emptyList();
        }

        // 获取宝宝基本信息
        BabyInfo babyInfo = new BabyInfo(babyId, "", "", LocalDate.now().minusMonths(3), LocalDate.now(), LocalDate.now(), 1L);

        // 按照月龄分组
        Map<Integer, List<BabyPhysicalIndicators>> monthGroupedMap = indicatorsList.stream()
                .collect(Collectors.groupingBy(indicator -> {
                    LocalDate measurementTime = indicator.getMeasurementTime();
                    return (int) ChronoUnit.MONTHS.between(babyInfo.getBirthDate(), measurementTime);
                }));

        // 用于存放最终每个月龄最新数据的列表
        List<BabyGrowthInfoVo> resultList = new ArrayList<>();
/*

        // 打印所有分组,月龄和详细信息
        System.out.println("所有分组：");
        monthGroupedMap.forEach((months, indicatorListForMonth) -> {
            System.out.println("月龄：" + months + ", 详细信息：" + indicatorListForMonth);
        });
*/

        // 遍历每个月龄分组
        monthGroupedMap.forEach((months, indicatorListForMonth) -> {
            // 在同一月龄的记录列表中找到测量时间最新的那条记录
            Optional<BabyPhysicalIndicators> latestIndicatorOptional = indicatorListForMonth.stream()
                    .max(Comparator.comparing(BabyPhysicalIndicators::getMeasurementTime));
/*
            // 打印当前月龄和对应的最新记录
            System.out.println("当前月龄：" + months);
            latestIndicatorOptional.ifPresent(latestIndicator -> {
                System.out.println("最新记录：" + latestIndicator);
            });*/

            // 如果找到了最新记录，则转换为BabyGrowthInfoVo并添加到结果列表中
            latestIndicatorOptional.ifPresent(latestIndicator -> {
                BabyGrowthInfoVo vo = new BabyGrowthInfoVo();
                vo.setBabyId(babyId);
                vo.setMonths(months);
                vo.setHeight(latestIndicator.getHeight());
                vo.setWeight(latestIndicator.getWeight());
                vo.setHeadAround(latestIndicator.getHeadAround());
                resultList.add(vo);
            });
        });

        return resultList;
    }

    /**
     * 根据babyId获取宝宝的年龄信息（根据measurement_time和birth_date对比）
     *
     * @param babyId
     * @return List<BabyAgeInfoVo>
     */
    @Override
    public List<BabyAgeInfoVo> getBabyAgeInfoByBabyId(Long babyId) {

        // 先从baby_info_table表查询baby的基本信息（主要获取birth_date）
        BabyInfo babyInfo = babyPhysicalIndicatorsDao.selectByBabyId(babyId);
        if (babyInfo == null) {
            return new ArrayList<>();
        }

        // 再根据babyId获取该宝宝的所有身体指标记录
        List<BabyPhysicalIndicators> indicatorsList = babyPhysicalIndicatorsDao.selectList(new QueryWrapper<BabyPhysicalIndicators>()
                .eq("baby_id", babyId));

        // 检查指标记录是否为空
        if (indicatorsList == null || indicatorsList.isEmpty()) {
            return new ArrayList<>();
        }
        // 遍历指标记录列表，计算每个记录对应的月龄和年龄信息，并添加到结果列表中
        List<BabyAgeInfoVo> resultList = new ArrayList<>();

        for (BabyPhysicalIndicators indicator : indicatorsList) {
            LocalDate measurementTime = indicator.getMeasurementTime();
            long monthsBetween = ChronoUnit.MONTHS.between(babyInfo.getBirthDate(), measurementTime);
            if (monthsBetween < 12) {
                Period period = Period.between(babyInfo.getBirthDate(), measurementTime);
                String ageInfo = period.getMonths() + "个月" + period.getDays() + "天";
                BabyAgeInfoVo vo = new BabyAgeInfoVo(babyId, measurementTime, ageInfo);
                resultList.add(vo);
            } else {
                long years = monthsBetween / 12;
                long remainingMonths = monthsBetween % 12;
                String ageInfo = years + "岁" + remainingMonths + "个月" + indicator.getMeasurementTime().getDayOfMonth() + "天";
                BabyAgeInfoVo vo = new BabyAgeInfoVo(babyId, measurementTime, ageInfo);
                resultList.add(vo);
            }
        }

        return resultList;
    }

    /**
     * 根据indicator_id获取对比结果及建议
     *
     * @param indicatorId
     * @return
     */
    @Override
    public ComparisonResultVo getComparisonResultByIndicatorId(Long indicatorId) {
        // 获取指定indicator_id的宝宝身体指标记录
        BabyPhysicalIndicators indicators = babyPhysicalIndicatorsDao.selectById(indicatorId);
        if (indicators == null) {
            return new ComparisonResultVo("未找到对应记录", "", "", "");
        }

        // 获取宝宝基本信息（主要为了获取性别和出生日期来查找标准数据）
        BabyInfo babyInfo = babyPhysicalIndicatorsDao.selectByBabyId(indicators.getBabyId());
        if (babyInfo == null) {
            return new ComparisonResultVo("", "", "", "无法获取宝宝基本信息，无法进行对比");
        }

        // 根据宝宝性别和月龄查询对应的标准数据
        int months = (int) LocalDate.now().until(indicators.getMeasurementTime()).toTotalMonths();
        List<BabyStandardData> standardDataList = babyStandardDataDao.selectByMonthRangeAndGender(months, babyInfo.getGender());
        if (standardDataList.isEmpty()) {
            return new ComparisonResultVo("", "", "", "未找到对应月龄的标准数据，无法进行对比");
        }

        // 取第一条标准数据（这里假设数据按合理逻辑配置，只取一条符合条件的用于对比）
        BabyStandardData standardData = standardDataList.get(0);

        // 比较身高
        String heightComparison = compareValue(indicators.getHeight(), standardData.getHeightPercent3(), standardData.getHeightPercent50(), standardData.getHeightPercent97());
        // 比较体重
        String weightComparison = compareValue(indicators.getWeight(), standardData.getWeightPercent3(), standardData.getWeightPercent50(), standardData.getWeightPercent97());
        // 比较头围（注意头围数据只记录到7个月对应的标准，这里需做相应判断）
        String headAroundComparison = "";
        if (months <= 7) {
            headAroundComparison = compareValue(indicators.getHeadAround(), standardData.getHeadAroundPercent3(), standardData.getHeadAroundPercent50(), standardData.getHeadAroundPercent97());
        }

        // 根据比较结果生成建议
        String suggestion = generateSuggestion(heightComparison, weightComparison, headAroundComparison);

        return new ComparisonResultVo(heightComparison, weightComparison, headAroundComparison, suggestion);
    }

    /**
     * 根据指标值和百分比范围判断是否偏胖/偏瘦/偏高/偏低，并返回比较结果
     *
     * @param actualValue   实际值
     * @param percent3      3%百分比对应的值
     * @param percent50     50%百分比对应的值
     * @param percent97     97%百分比对应的值
     * @return 比较结果（偏胖/偏瘦/偏高/偏低）
     */
    private String compareValue(BigDecimal actualValue, BigDecimal percent3, BigDecimal percent50, BigDecimal percent97) {
        if (actualValue.compareTo(percent3) < 0) {
            return "偏低";
        } else if (actualValue.compareTo(percent97) > 0) {
            return "偏高";
        } else if (actualValue.compareTo(percent50) > 0) {
            return "偏胖/偏高（相对平均水平）";
        } else if (actualValue.compareTo(percent50) < 0) {
            return "偏瘦/偏低（相对平均水平）";
        }
        return "正常";
    }

    // 辅助方法: 用于根据比较结果生成建议
    private String generateSuggestion(String heightComparison, String weightComparison, String headAroundComparison) {
        // 对输入参数进行空值检查
        if (heightComparison == null) heightComparison = "";
        if (weightComparison == null) weightComparison = "";
        if (headAroundComparison == null) headAroundComparison = "";

        // 构建建议字符串,用来拼接建议
        StringBuilder sb = new StringBuilder();

        // 提取公共逻辑
        appendIfMatch(sb, "偏低", heightComparison, "身体偏低，");
        appendIfMatch(sb, "偏高", heightComparison, "宝宝长得很高，");

        appendIfMatch(sb, "偏瘦/偏低（相对平均水平）", weightComparison, "体重偏瘦，");
        appendIfMatch(sb, "偏胖/偏高（相对平均水平）", weightComparison, "体重偏胖，");

        appendIfMatch(sb, "偏低", headAroundComparison, "头围偏小，");
        appendIfMatch(sb, "偏高", headAroundComparison, "头围偏大，");

        // 如果有建议，删除最后一个逗号并添加提示
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
            sb.append("，请注意一下baby的身体状况。");
        } else {
            sb.append("宝宝的身体状况正常，请注意保持健康。");
        }

        return sb.toString();
    }

    // 辅助方法: 用于根据匹配情况添加建议
    private void appendIfMatch(StringBuilder sb, String match, String comparison, String suggestion) {
        if (match.equals(comparison)) {
            sb.append(suggestion);
        }
    }

}